//==================================================================================================
/**
  EVE - Expressive Vector Engine
  Copyright : EVE Project Contributors
  SPDX-License-Identifier: BSL-1.0
**/
//==================================================================================================
#include "test.hpp"

#include <eve/module/core.hpp>
#include <eve/module/math.hpp>

#include <cmath>

//==================================================================================================
// Types tests
//==================================================================================================
TTS_CASE_TPL("Check return types of cos", eve::test::simd::ieee_reals)
<typename T>(tts::type<T>)
{
  using v_t = eve::element_type_t<T>;

  TTS_EXPR_IS(eve::sincos(T()), (eve::wide<kumi::tuple<v_t, v_t>,typename T::cardinal_type>));
  TTS_EXPR_IS(eve::sincos(v_t()), (kumi::tuple<v_t, v_t>));
};

//==================================================================================================
// cos  tests
//==================================================================================================
auto mquarter_c = []<typename T>(eve::as<T> const& tgt) { return -eve::pio_4(tgt); };
auto quarter_c  = []<typename T>(eve::as<T> const& tgt) { return  eve::pio_4(tgt); };
auto mhalf_c    = []<typename T>(eve::as<T> const& tgt) { return -eve::pio_2(tgt); };
auto half_c     = []<typename T>(eve::as<T> const& tgt) { return  eve::pio_2(tgt); };
auto mfull_c    = []<typename T>(eve::as<T> const& tgt) { return -eve::pi(tgt); };
auto full_c     = []<typename T>(eve::as<T> const& tgt) { return  eve::pi(tgt); };
auto mmed       = []<typename T>(eve::as<T> const& tgt) { return -eve::Rempio2_limit[eve::medium](tgt); };
auto med        = []<typename T>(eve::as<T> const& tgt) { return  eve::Rempio2_limit[eve::medium](tgt); };

TTS_CASE_WITH("Check behavior of cos on wide",
              eve::test::simd::ieee_reals,
              tts::generate(tts::randoms(tts::constant(mquarter_c), tts::constant(quarter_c)),
                            tts::randoms(tts::constant(mhalf_c), tts::constant(half_c)),
                            tts::randoms(tts::constant(mfull_c), tts::constant(full_c)),
                            tts::randoms(tts::constant(mmed), tts::constant(med)),
                            tts::randoms(eve::valmin, eve::valmax)))
<typename T>(T const& a0, T const& a1, T const& a2, T const& a3, T const& a4)
{
  using eve::sincos;

  using v_t = eve::element_type_t<T>;
  auto refc = [](auto e) -> v_t { return std::cos(e); };
  auto refs = [](auto e) -> v_t { return std::sin(e); };
  {
    auto [s, c] = sincos[eve::quarter_circle](a0);
    TTS_ULP_EQUAL(s, tts::map(refs, a0), 2);
    TTS_ULP_EQUAL(c, tts::map(refc, a0), 2);
  }
  {
    auto [s, c] = sincos[eve::half_circle](a0);
    TTS_ULP_EQUAL(s, tts::map(refs, a0), 2);
    TTS_ULP_EQUAL(c, tts::map(refc, a0), 2);
    auto [s1, c1] = sincos[eve::half_circle](a1);
    TTS_ULP_EQUAL(s1, tts::map(refs, a1), 2);
    TTS_ULP_EQUAL(c1, tts::map(refc, a1), 2);
  }
  {
    auto [s, c] = sincos[eve::full_circle](a0);
    TTS_ULP_EQUAL(s, tts::map(refs, a0), 2);
    TTS_ULP_EQUAL(c, tts::map(refc, a0), 2);
    auto [s1, c1] = sincos[eve::full_circle](a1);
    TTS_ULP_EQUAL(s1, tts::map(refs, a1), 2);
    TTS_ULP_EQUAL(c1, tts::map(refc, a1), 2);
    auto [s2, c2] = sincos[eve::full_circle](a2);
    TTS_ULP_EQUAL(s2, tts::map(refs, a2), 2);
    TTS_ULP_EQUAL(c2, tts::map(refc, a2), 2);
  }
  {
    auto [s, c] = sincos(a0);
    TTS_ULP_EQUAL(s, tts::map(refs, a0), 2);
    TTS_ULP_EQUAL(c, tts::map(refc, a0), 2);
    auto [s1, c1] = sincos(a1);
    TTS_ULP_EQUAL(s1, tts::map(refs, a1), 2);
    TTS_ULP_EQUAL(c1, tts::map(refc, a1), 2);
    auto [s2, c2] = sincos(a2);
    TTS_ULP_EQUAL(s2, tts::map(refs, a2), 2);
    TTS_ULP_EQUAL(c2, tts::map(refc, a2), 2);
    auto [s3, c3] = sincos(a3);
    TTS_ULP_EQUAL(s3, tts::map(refs, a3), 2);
    TTS_ULP_EQUAL(c3, tts::map(refc, a3), 2);
    auto [s4, c4] = sincos(a4);
    TTS_ULP_EQUAL(s4, tts::map(refs, a4), 2);
    TTS_ULP_EQUAL(c4, tts::map(refc, a4), 2);
  }
};
